package com.pvdnc.nsocket.init;

import com.pvdnc.encrypt.IEncrypt;
import com.pvdnc.nsocket.EndPoint;
import com.pvdnc.nsocket.ManagedChannel;
import com.pvdnc.nsocket.log.SLog;
import com.pvdnc.nsocket.protocol.Decoder;
import com.pvdnc.nsocket.protocol.Encoder;
import com.pvdnc.nsocket.protocol.base.Packet;
import com.pvdnc.nsocket.protocol.Splitter;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

public abstract class CSInitializer extends ChannelInitializer<NioSocketChannel> {
    private static final SLog LOG=new SLog(CSInitializer.class);

    private final Map<String,EventLoopGroup> mLoopGroupMap =new HashMap<>();

    protected NioEventLoopGroup mAcceptLoop=new NioEventLoopGroup();
    protected NioEventLoopGroup mClientLoop=new NioEventLoopGroup();

    private IEncrypt mFullEncrypt;

    public IEncrypt getFullEncrypt() {
        return mFullEncrypt;
    }

    private EndPoint mEndPoint;

    public int getPort(){
        return mEndPoint.getPort();
    }

    public String getHost(){
        return mEndPoint.getHost();
    }

    public EndPoint getEndPoint(){
        return mEndPoint;
    }

    public CSInitializer(EndPoint endPoint,IEncrypt fullEncrypt){
        mEndPoint=endPoint;
        mFullEncrypt=fullEncrypt;
    }

    private void shutdownAllEventGroup(){
        mAcceptLoop.shutdownGracefully();
        mClientLoop.shutdownGracefully();
    }

    private ManagedChannel mChannel;

    public void setChannel(Channel channel){
        mChannel=ManagedChannel.getInstance(channel);
        setRunning(true);
    }

    @Override
    protected void initChannel(NioSocketChannel ch) throws Exception {
        LOG.d("init channel:"+ch);
        ChannelPipeline pipeline = ch.pipeline();
        //添加通用Handler
        pipeline.addLast(new Splitter());
        pipeline.addLast(new Decoder());
        addWorkHandlers(pipeline);
        pipeline.addLast(new Encoder());
        LOG.d("handler map:\n\t"+pipeline.toMap());
    }

    public abstract void addWorkHandlers(ChannelPipeline pipeline);

    public <T extends Packet> void send(T packet,boolean needToWait){
       mChannel.send(packet,needToWait);
    }

    private boolean mRunning;

    public boolean isRunning(){
        synchronized (this) {
            return mRunning;
        }
    }

    public void setRunning(boolean running){
        synchronized (this) {
            mRunning = running;
        }
        LOG.d("running status:"+running);
    }

    public abstract Packet onPreClose();

    public void onPostClose(){
        LOG.d("on post close");
        setRunning(false);
        shutdownAllEventGroup();
    }

    public void doClose(){
        mChannel.close(onPreClose(), new Runnable() {
            @Override
            public void run() {
                onPostClose();
            }
        });
    }
}
